package org.example.sunrise.views.models;

import javafx.scene.canvas.GraphicsContext;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.stage.WindowEvent;
import org.example.sunrise.sprites.PeashooterBullet;
import org.example.sunrise.sprites.Sprite;
import org.example.sunrise.sprites.Sun;
import org.example.sunrise.sprites.plants.Sunflower;
import org.example.sunrise.sprites.plants.Peashooter;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

public class SimpleGameViewModel {
    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(4);
    private int sunValues = 0;
    private final List<Sprite> sprites = new ArrayList<>();
    private Sprite plantChosen;

    public SimpleGameViewModel() {
        initialize();
    }

    public void initialize() {
        sprites.add(new Sprite("other/grassTiles.png"));
        sprites.add(new Sprite("other/plantChosenList.jpeg", 280, 87));
        sprites.add(new Sprite("other/pauseButton.png") {{
            setPositionX(681);
        }});
        sprites.add(createPlantChosen(97, 9, Peashooter::new));
        sprites.add(createPlantChosen(156, 9, Sunflower::new));
    }

    public void render(GraphicsContext gc) {
        renderSprites(gc);
        renderSunValues(gc);
    }

    private void renderSprites(GraphicsContext gc) {
        synchronized (sprites) {
            sprites.removeIf(Sprite::isNeedDestroy);
            sprites.forEach(sprite -> {
                sprite.update();
                gc.save();
                gc.translate(sprite.getPositionX(), sprite.getPositionY());
                if (sprite.getImage() != null) {
                    gc.drawImage(sprite.getImage(), 0, 0);
                }
                gc.restore();
            });
        }
    }

    private void renderSunValues(GraphicsContext gc) {
        gc.setFont(new Font(20));
        gc.setFill(Color.LIGHTGOLDENRODYELLOW);
        gc.fillRect(21, 60, 56, 21);
        gc.setFill(Color.BLACK);
        gc.fillText(String.valueOf(sunValues), 33, 78, 37);
    }

    private ScheduledFuture<?> generateSun(Sprite sprite) {
        Optional<Sprite> sunflower = Optional.ofNullable(sprite);
        return scheduler.scheduleAtFixedRate(() -> {
            Sun sun = new Sun();
            sunflower.ifPresent(s -> {
                sun.setPositionX(s.getPositionX());
                sun.setPositionY(s.getPositionY());
                sun.setBound(s.getPositionY());
            });
            sun.addOnClickListener(this::collectSun);
            synchronized (sprites) {
                sprites.add(sun);
            }
            scheduler.schedule(() -> sun.setNeedDestroy(true), 6, TimeUnit.SECONDS);
        }, 2, 10, TimeUnit.SECONDS);
    }

    private ScheduledFuture<?> generateBullet(Sprite sprite) {
        return scheduler.scheduleAtFixedRate(() -> {
            PeashooterBullet bullet = new PeashooterBullet();
            bullet.setPositionX(sprite.getPositionX() + 55);
            bullet.setPositionY(sprite.getPositionY() + 5);
            synchronized (sprites) {
                sprites.add(bullet);
            }
        }, 1, 6, TimeUnit.SECONDS);
    }

    private void switchImage() {
        scheduler.scheduleAtFixedRate(() -> {
            synchronized (sprites) {
                sprites.forEach(Sprite::switchImage);
            }
        }, 0, 100, TimeUnit.MILLISECONDS);
    }

    public void runTask() {
        generateSun(null);
        switchImage();
    }

    public void stopTask(WindowEvent evt) {
        scheduler.shutdownNow();
    }

    public void onMouseClicked(MouseEvent evt) {
        final double x = evt.getX();
        final double y = evt.getY();
        synchronized (sprites) {
            sprites.forEach(sprite -> {
                if (sprite.isChosen(x, y)) {
                    sprite.onMouseClicked();
                }
                if (plantChosen == sprite) {
                    if (plantChosen instanceof Sunflower sunflower) {
                        sunflower.setFuture(generateSun(sunflower));
                    }
                    if (plantChosen instanceof Peashooter peashooter) {
                        peashooter.setFuture(generateBullet(peashooter));
                    }
                    plantChosen = null;
                }
            });
            if (plantChosen != null && !sprites.contains(plantChosen)) {
                sprites.add(plantChosen);
            }
        }
    }

    private void collectSun(Sprite sprite) {
        sprite.setNeedDestroy(true);
        sunValues += 25;
    }

    public void onMouseMoved(MouseEvent evt) {
        if (plantChosen != null) {
            plantChosen.setPositionX(evt.getX() - plantChosen.getWidth() / 2);
            plantChosen.setPositionY(evt.getY() - plantChosen.getHeight() / 2);
        }
    }

    public Sprite createPlantChosen(double x, double y, Supplier<Sprite> supplier) {
        Sprite sprite = new Sprite();
        sprite.setPositionX(x);
        sprite.setPositionY(y);
        sprite.setHeight(68);
        sprite.setWidth(48);
        sprite.addOnClickListener(s -> {
            plantChosen = supplier.get();
            plantChosen.setPositionX(s.getPositionX());
            plantChosen.setPositionY(s.getPositionY());
        });
        return sprite;
    }
}
